import { expect, test } from 'vitest';

import { cached_test, describe_cached } from "./env";
import { selectorsFromBytecode } from '../index';
import { disasm } from '../disasm';

//const address = "0xbadc0defafcf6d4239bdf0b66da4d7bd36fcf05a";
//const missingSelector = "0x69277b67";


//const address = "0x00000000006c3852cbEf3e08E8dF289169EdE581";
//const extraSelector = "0x06fdde03";

//const address = "0x388c818ca8b9251b393131c08a736a67ccb19297"
//const missingSelectorJump = "0x8980f11f";

test('code with deploy init', () => {
  // https://github.com/shazow/whatsabi/issues/19#issuecomment-1498767496 
  const code = "60806040526000805534801561001457600080fd5b50610178806100246000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806329e46078146100675780634e148ce11461009a57806368e5c066146100cd578063a87d942c146100e4575b600080fd5b34801561007357600080fd5b50610098600480360381019080803563ffffffff16906020019092919050505061010f565b005b3480156100a657600080fd5b506100cb600480360381019080803563ffffffff169060200190929190505050610122565b005b3480156100d957600080fd5b506100e2610135565b005b3480156100f057600080fd5b506100f9610143565b6040518082815260200191505060405180910390f35b8060020263ffffffff1660008190555050565b8060010263ffffffff1660008190555050565b600160005401600081905550565b600080549050905600a165627a7a72305820946aaa67044121e8026c839756e8dc0bcd00731a5c7239ace3524046974de6720029";

  const r = selectorsFromBytecode(code);
  r.sort();

  expect(r).toEqual(["0x29e46078", "0x4e148ce1", "0x68e5c066", "0xa87d942c"]);
})

test('code with non payable guard before router', () => {
  // https://github.com/shazow/whatsabi/issues/19#issuecomment-1500383369
  const code = "608060405234801561001057600080fd5b506004361061004c5760003560e01c806329e46078146100515780634e148ce11461008557806368e5c066146100b9578063a87d942c146100c3575b600080fd5b6100836004803603602081101561006757600080fd5b81019080803563ffffffff1690602001909291905050506100e1565b005b6100b76004803603602081101561009b57600080fd5b81019080803563ffffffff1690602001909291905050506100f4565b005b6100c1610107565b005b6100cb610115565b6040518082815260200191505060405180910390f35b8060020263ffffffff1660008190555050565b8060010263ffffffff1660008190555050565b600160005401600081905550565b6000805490509056fea26469706673582212204c69a9d6b5cb7799cdc0b4ac099047de21c79769b6be631679204f0e5bd74a0c64736f6c63430006000033";
  const r = selectorsFromBytecode(code);
  r.sort();

  expect(r).toEqual(["0x29e46078", "0x4e148ce1", "0x68e5c066", "0xa87d942c"]);
})

test('code with immutable in solidity', () => {
  // Via https://twitter.com/RenanRSouza35/status/1644308118375915523
  /*
    contract Foo {
        uint public immutable a;

        constructor(uint _a) {
            a = _a;
        }
    }
  */
  const code = "60a060405234801561001057600080fd5b506040516101913803806101918339818101604052810190610032919061007b565b8060808181525050506100a8565b600080fd5b6000819050919050565b61005881610045565b811461006357600080fd5b50565b6000815190506100758161004f565b92915050565b60006020828403121561009157610090610040565b5b600061009f84828501610066565b91505092915050565b60805160d16100c060003960006049015260d16000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80630dbe671f14602d575b600080fd5b60336047565b604051603e91906082565b60405180910390f35b7f000000000000000000000000000000000000000000000000000000000000000081565b6000819050919050565b607c81606b565b82525050565b6000602082019050609560008301846075565b9291505056fea2646970667358fe1220fefe877c7ce1496f641a93e2d422be3341a5980ffe704ad09a703dbf0bb1656d64736f6c63430008110033";
  const r = selectorsFromBytecode(code);
  r.sort();

  expect(r).toEqual([
    "0x0dbe671f" // a()
  ]);
})

test('issue 42', () => {
  // https://github.com/shazow/whatsabi/issues/42
  // https://etherscan.io/address/0x37c6e59e1ae39d81828db1a8e8233d6b2afcb9a8
  const bytecode = "0x5b602960346000f073032be5d2772329c11a72dadb32ce03806bb26f0a3160005760006000600060003031335af15060006000f36000600060206000600073032be5d2772329c11a72dadb32ce03806bb26f0a5a6069600052f15033ff";
  const r = selectorsFromBytecode(bytecode);
  expect(r).toEqual([
  ]);
});

import { WANDERWING } from './__fixtures__/proxies';
test('issue 67', () => {
  const bytecode = WANDERWING;
  const r = selectorsFromBytecode(bytecode);
  expect(r).toEqual([
  ]);
});

cached_test('issue 70: negated selector', async ({ provider, withCache }) => {
  const address = "0x000000000090d2b159528c290616CF919B24e1d9";

  const code = await withCache(
    `${address}_code`,
    async () => {
      return await provider.getCode(address)
    },
  )

  const r = selectorsFromBytecode(code);
  expect(r).toEqual(expect.arrayContaining(["0xfd9f1e10"]))
});

cached_test('issue 146: duplicated events', async ({ provider, withCache }) => {
  const address = "0xd9db270c1b5e3bd161e8c8503c55ceabee709552";

  const code = await withCache(
    `${address}_code`,
    async () => {
      return await provider.getCode(address)
    },
  )

  const r = disasm(code);
  expect(Array.from(r.eventCandidates).length).toEqual(14);
});

test('issue 171: immutable EIP1967 proxy', () => {
  // https://github.com/shazow/whatsabi/issues/171
  // createCode from https://etherscan.io/address/0x6f943318b05AD7c6EE596A220510A6D64B518dd8
  const createCode = "60a06040526040516105bf3803806105bf83398101604081905261002291610387565b61002c828261003e565b506001600160a01b031660805261047e565b610047826100fe565b6040516001600160a01b038316907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a28051156100f2576100ed826001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100e79190610447565b82610211565b505050565b6100fa610288565b5050565b806001600160a01b03163b60000361013957604051631933b43b60e21b81526001600160a01b03821660048201526024015b60405180910390fd5b807fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5080546001600160a01b0319166001600160a01b0392831617905560408051635c60da1b60e01b81529051600092841691635c60da1b9160048083019260209291908290030181865afa1580156101b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d99190610447565b9050806001600160a01b03163b6000036100fa57604051634c9c8ce360e01b81526001600160a01b0382166004820152602401610130565b6060600080846001600160a01b03168460405161022e9190610462565b600060405180830381855af49150503d8060008114610269576040519150601f19603f3d011682016040523d82523d6000602084013e61026e565b606091505b50909250905061027f8583836102a9565b95945050505050565b34156102a75760405163b398979f60e01b815260040160405180910390fd5b565b6060826102be576102b982610308565b610301565b81511580156102d557506001600160a01b0384163b155b156102fe57604051639996b31560e01b81526001600160a01b0385166004820152602401610130565b50805b9392505050565b8051156103185780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b80516001600160a01b038116811461034857600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561037e578181015183820152602001610366565b50506000910152565b6000806040838503121561039a57600080fd5b6103a383610331565b60208401519092506001600160401b03808211156103c057600080fd5b818501915085601f8301126103d457600080fd5b8151818111156103e6576103e661034d565b604051601f8201601f19908116603f0116810190838211818310171561040e5761040e61034d565b8160405282815288602084870101111561042757600080fd5b610438836020830160208801610363565b80955050505050509250929050565b60006020828403121561045957600080fd5b61030182610331565b60008251610474818460208701610363565b9190910192915050565b6080516101276104986000396000601e01526101276000f3fe6080604052600a600c565b005b60186014601a565b60a0565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156079573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190609b919060c3565b905090565b3660008037600080366000845af43d6000803e80801560be573d6000f35b3d6000fd5b60006020828403121560d457600080fd5b81516001600160a01b038116811460ea57600080fd5b939250505056fea2646970667358221220ba4584e06302b35e8111d9457f4e63fa0ab53461d8999af0dbc529c45465719264736f6c6343000819003300000000000000000000000028e06ce6b25529e736d45aff7c82ef4fc6f710be000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a4fab57b8f0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000bdc312acd6b13f28d3a17c87a07b93d056a3236d00000000000000000000000074d9fb2b522cf886872ac333480dc4779a4bb21400000000000000000000000017e49fe369062d1eeca9564e5451021da778739b0000000000000000000000007e39183cda5af65e6a18af8c3bf0c523127f83bf000000000000000000000000604ffe37a969042c86ff0b10b2d2c4ea987d6f1d0000000000000000000000002c610e4c3c4bd4d6b76d4c7ce5e376b865c35660000000000000000000000000135dda560e946695d6f155dacafc6f1f25c1f5af000000000000000000000000bfef6e99e7dd8538ae9741d91ce27a486948aa8200000000000000000000000000000000000000000000000000000000000001400000000000000000000000004368f8f944430519f2222b0458f48ad287a83230000000000000000000000000000000000000000000000000000000000000001972656473746f6e652d6176732d6d61696e6e65742d626173650000000000000000000000000000000000000000000000000000000000000000000000";
  const r = disasm(createCode);
  expect(r.init).toBeDefined();
  expect(r.init?.proxies.length).toBeGreaterThan(0);
  expect(r.proxies.length).toBeGreaterThan(0);
  expect(r.proxies[0].name).toEqual("EIP1967Proxy");
});

test('issue 178: EIP1967 off-by-one', () => {
  // https://github.com/shazow/whatsabi/issues/178
  // bytecode from https://basescan.org/address/0xfe742fa2a84294e8316f05b17c05090fc68b5105
  const createCode = "0x60806040526004361061004a5760003560e01c80633659cfe6146100545780634f1ef286146100745780635c60da1b14610087578063d1f57894146100b8578063f851a440146100cb575b6100526100e0565b005b34801561006057600080fd5b5061005261006f36600461053e565b610108565b610052610082366004610560565b61014c565b34801561009357600080fd5b5061009c610202565b6040516001600160a01b03909116815260200160405180910390f35b6100526100c63660046105f9565b610253565b3480156100d757600080fd5b5061009c610341565b6100e8610398565b6101066101016000805160206107388339815191525490565b6103a0565b565b6001600160a01b037f0000000000000000000000005731a04b1e775f0fdd454bf70f3335886e9a96be16330361014457610141816103c4565b50565b6101416100e0565b6001600160a01b037f0000000000000000000000005731a04b1e775f0fdd454bf70f3335886e9a96be1633036101f557610185836103c4565b6000836001600160a01b031683836040516101a19291906106bb565b600060405180830381855af49150503d80600081146101dc576040519150601f19603f3d011682016040523d82523d6000602084013e6101e1565b606091505b50509050806101ef57600080fd5b50505050565b6101fd6100e0565b505050565b60006001600160a01b037f0000000000000000000000005731a04b1e775f0fdd454bf70f3335886e9a96be16330361024857506000805160206107388339815191525490565b6102506100e0565b90565b600061026b6000805160206107388339815191525490565b6001600160a01b03161461027e57600080fd5b6102a960017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd6106cb565b600080516020610738833981519152146102c5576102c56106f2565b6102ce82610404565b80511561033d576000826001600160a01b0316826040516102ef9190610708565b600060405180830381855af49150503d806000811461032a576040519150601f19603f3d011682016040523d82523d6000602084013e61032f565b606091505b50509050806101fd57600080fd5b5050565b60006001600160a01b037f0000000000000000000000005731a04b1e775f0fdd454bf70f3335886e9a96be16330361024857507f0000000000000000000000005731a04b1e775f0fdd454bf70f3335886e9a96be90565b61010661048f565b3660008037600080366000845af43d6000803e8080156103bf573d6000f35b3d6000fd5b6103cd81610404565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b803b61047d5760405162461bcd60e51b815260206004820152603b60248201527f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f60448201527f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000060648201526084015b60405180910390fd5b60008051602061073883398151915255565b6001600160a01b037f0000000000000000000000005731a04b1e775f0fdd454bf70f3335886e9a96be1633036101065760405162461bcd60e51b815260206004820152603260248201527f43616e6e6f742063616c6c2066616c6c6261636b2066756e6374696f6e20667260448201527137b6903a343290383937bc3c9030b236b4b760711b6064820152608401610474565b80356001600160a01b038116811461053957600080fd5b919050565b60006020828403121561055057600080fd5b61055982610522565b9392505050565b60008060006040848603121561057557600080fd5b61057e84610522565b9250602084013567ffffffffffffffff8082111561059b57600080fd5b818601915086601f8301126105af57600080fd5b8135818111156105be57600080fd5b8760208285010111156105d057600080fd5b6020830194508093505050509250925092565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561060c57600080fd5b61061583610522565b9150602083013567ffffffffffffffff8082111561063257600080fd5b818501915085601f83011261064657600080fd5b813581811115610658576106586105e3565b604051601f8201601f19908116603f01168101908382118183101715610680576106806105e3565b8160405282815288602084870101111561069957600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b8183823760009101908152919050565b818103818111156106ec57634e487b7160e01b600052601160045260246000fd5b92915050565b634e487b7160e01b600052600160045260246000fd5b6000825160005b81811015610729576020818601810151858301520161070f565b50600092019182525091905056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212203afa1b8aed7b7ea806f127a3328a650ea6fea862aa0b9edcdd49a3aeab8c328b64736f6c63430008130033";
  const r = disasm(createCode);
  expect(r.proxies.length).toBeGreaterThan(0);
  expect(r.proxies[0].name).toEqual("EIP1967Proxy");
});

// Addresses with false positive zero selectors:
// 0x99aa182ed0e2b6c47132e95686d2c73cdeff307f
// 0xb1116d0a09f06d3e22a264c0c233d80e93abec10
// 0xb60e36e2d67a34b4eae678cad779e281e4c6d58c
